﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using NPMonitor.DataModel;
using NPMonitor.Implementation.Internal;
using NPMonitor.Interfaces;

namespace NPMonitor.Implementation.Store
{
    public class WorkflowStore : IWorkflowStore
    {
        public List<WorkflowJobData> GetWorkflowsContainSpecificJob(int jobId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.WorkflowJobs.Where(x => x.JobId == jobId).ToList();
            }
        }

        /// <summary>
        /// build temporary job instance by workflow job
        /// </summary>
        /// <param name="wfJob"></param>
        /// <returns></returns>
        public JobData CreateTempJobData(WorkflowJobData wfJob)
        {
            JobData jdata = null;

            DateTime now = Helpers.Utils.CurrentServerUtcTime;
            JobDefinition jd = StoreManager.Current.JobDefinitionStore.GetJobDefinitionById(wfJob.JobId);

            if (jd != null)
            {
                jdata = new JobData()
                {
                    Description = jd.Desc,
                    TaskId = wfJob.JobId,
                    JobTaskType = NPMonitor.TaskType.Job,
                    UniqueId = Guid.NewGuid(),
                    CreatedDate = now,
                    IsDelete = false
                };
            }

            return jdata;
        }

        /// <summary>
        /// 根据workflowId获取Workflow下的所有job
        /// </summary>
        /// <param name="workflowId"></param>
        /// <returns></returns>
        public List<WorkflowJobData> GetWorkflowJobDataByWorkflowId(int workflowId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.WorkflowJobs.Where(x => x.WorkflowId == workflowId).OrderBy(p => p.Sequence).ToList();
            }
        }

        /// <summary>
        /// 保持Workflow信息，及Workflow下的job记录
        /// </summary>
        /// <param name="workflowData"></param>
        /// <param name="jobItems"></param>
        /// <returns></returns>
        public void SaveWorkflowInfo(WorkflowData workflowData, List<WorkflowJobItem> jobItems)
        {
            using (var ts = new TransactionScope())
            {
                //操作数据
                using (var ctx = new DbStoreContext())
                {
                    //创建新的Workflow
                    if (workflowData.WorkflowId == null)
                    {
                        workflowData.CreateTime = Helpers.Utils.CurrentServerUtcTime;
                        ctx.Workflows.Add(workflowData);
                    }
                    else
                    {
                        //更新Workflow
                        WorkflowData data = ctx.Workflows.FirstOrDefault(p => p.WorkflowId == workflowData.WorkflowId);
                        if (data == null)
                           throw new Exception("Operation failed!!!");

                        data.WorkflowName = workflowData.WorkflowName;
                        data.Description = workflowData.Description;
                        data.UpdateTime = Helpers.Utils.CurrentServerUtcTime;
                        data.UpdateBy = workflowData.UpdateBy;
                    }
                    ctx.SaveChanges();

                    //Workflow Job,如果job列表大于0，则对workflow下的job处理
                    if (jobItems.Count > 0)
                    {
                        //先删除job
                        int newCount = jobItems.Count();
                        int oldCount = ctx.WorkflowJobs.Count(p => p.WorkflowId == workflowData.WorkflowId);
                        //比较旧记录是否比新记录多，多则执行删除
                        if (oldCount > newCount)
                        {
                            //多出的记录数
                            int deleteCount = oldCount - newCount;
                            //查找当前Workflow下，最大的Sequence
                            int maxSequence = ctx.WorkflowJobs.Where(p => p.WorkflowId == workflowData.WorkflowId).Max(p => p.Sequence);
                            for (int i = 0; i < deleteCount; i++)
                            {
                                //查找当前Workflow下，Sequence最大的记录，并删除
                                WorkflowJobData tempJobData = ctx.WorkflowJobs.FirstOrDefault(p => p.WorkflowId == workflowData.WorkflowId && p.Sequence == maxSequence);
                                ctx.WorkflowJobs.Remove(tempJobData);
                                maxSequence--;
                            }
                        }

                        foreach (WorkflowJobItem item in jobItems)
                        {
                            WorkflowJobData jobData = ctx.WorkflowJobs.FirstOrDefault(p => p.WorkflowId == workflowData.WorkflowId && p.Sequence == item.Sequence);

                            //创建新的Workflow Job
                            if (jobData == null)
                            {
                                jobData = new WorkflowJobData();
                                jobData.JobId = item.JobId;
                                jobData.JobName = item.JobName;
                                jobData.Sequence = item.Sequence;
                                jobData.FailureAction = item.FailureAction;
                                jobData.WorkflowId = workflowData.WorkflowId.Value;
                                ctx.WorkflowJobs.Add(jobData);
                            }
                            else
                            {
                                //更新新的Workflow Job
                                jobData.JobId = item.JobId;
                                jobData.JobName = item.JobName;
                                jobData.Sequence = item.Sequence;
                                jobData.FailureAction = item.FailureAction;
                                jobData.WorkflowId = workflowData.WorkflowId.Value;
                            }
                        }
                    }
                    else
                    {
                        //如果job列表大于0，则对workflow下的job做全部删除处理
                        List<int> deleteList = ctx.WorkflowJobs.Where(p => p.WorkflowId == workflowData.WorkflowId).Select(p => p.Id).ToList();
                        if (deleteList.Count > 0)
                        {
                            foreach (int deleteId in deleteList)
                            {
                                WorkflowJobData tempJobData = ctx.WorkflowJobs.FirstOrDefault(p => p.Id == deleteId);
                                ctx.WorkflowJobs.Remove(tempJobData);
                            }
                        }
                    }
                    ctx.SaveChanges();
                    ts.Complete();
                }
            }
        }

        /// <summary>
        /// 创建或修改Workflow时，验证检查
        /// </summary>
        /// <param name="workflowData"></param>
        /// <param name="jobItems"></param>
        /// <returns></returns>
        private ValidationResult ValidateWorkflowData(WorkflowData workflowData, List<WorkflowJobItem> jobItems)
        {
            //验证
            if (String.IsNullOrEmpty(workflowData.WorkflowName))
            {
                return new ValidationResult(false, "Require Workflow Name!", "REQ_WorkflowName");
            }
            if (jobItems.Count() <= 0)
            {
                return new ValidationResult(false, "Please select one job!", "REQ_SelectJob");
            }
            using (var ctx = new DbStoreContext())
            {
                if (workflowData.WorkflowId == null)
                {
                    //创建新Workflow时，检查是否存在workflow name
                    if (ctx.Workflows.FirstOrDefault(p => p.WorkflowName.Trim() == workflowData.WorkflowName.Trim()) != null)
                    {
                        return new ValidationResult(false, "Workflow name already exists!", "DUP_WorkflowName");
                    }
                }
                else
                {
                    //修改Workflow时，除自己的workflow name外，检查是否存在workflow name
                    WorkflowData tempWorkflowData = ctx.Workflows.FirstOrDefault(p => p.WorkflowId == workflowData.WorkflowId);
                    if (tempWorkflowData != null && string.Compare(workflowData.WorkflowName.Trim(), tempWorkflowData.WorkflowName.Trim(), true) != 0)
                    {
                        if (ctx.Workflows.FirstOrDefault(p => p.WorkflowName.Trim() == workflowData.WorkflowName.Trim()) != null)
                        {
                            return new ValidationResult(false, "Workflow name already exists!", "DUP_WorkflowName");
                        }
                    }
                }
            }

            return new ValidationResult(true);
        }

        /// <summary>
        /// 根据Workflow id 获取Workflow信息
        /// </summary>
        /// <param name="workflowId"></param>
        /// <returns></returns>
        public WorkflowData GetWorkflowDataById(int workflowId)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Workflows.FirstOrDefault(p => p.WorkflowId == workflowId);
            }
        }

        /// <summary>
        /// 根据Workflow name 获取Workflow信息
        /// </summary>
        /// <param name="workflowName"></param>
        /// <returns></returns>
        public WorkflowData GetWorkflowDataByName(string workflowName)
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Workflows.FirstOrDefault(p => p.WorkflowName.Trim() == workflowName.Trim());
            }
        }

        /// <summary>
        /// get workflow count
        /// </summary>
        /// <returns></returns>
        public int GetCountofWorkflow()
        {
            using (var ctx = new DbStoreContext())
            {
                return ctx.Workflows.Count();
            }
        }

        public List<WorkflowData> GetAllWorkflow(int pageIndex, int pageSize)
        {
            List<WorkflowData> list = new List<WorkflowData>();
            if (pageIndex < 0)
            {
                pageIndex = 0;
            }

            if (pageSize < 0)
            {
                pageSize = int.MaxValue;
            }
            using (var ctx = new DbStoreContext())
            {
                var workflows = from p in ctx.Workflows
                                select p;
                list = workflows.OrderByDescending(d => d.WorkflowId).Skip(pageIndex * pageSize).Take(pageSize).ToList();
            }
            return list;
        }

        public bool DeleteWorkflow(int id)
        {
            using (var ctx = new DbStoreContext())
            {
                var workflow = ctx.Workflows.Find(id);
                var workflowJob = ctx.WorkflowJobs.Where(d => d.WorkflowId == id);
                ctx.Workflows.Remove(workflow);
                if (workflowJob != null)
                {
                    foreach (var p in workflowJob)
                    {
                        ctx.WorkflowJobs.Remove(p);
                    }
                }
                ctx.SaveChanges();
            }
            return true;
        }
    }
}
